本系列將介紹 Rails with Vue 的基本概念,並且以一個簡單的專案 Todo 來說明如何使用 Rails with Vue。我將透過這一系列的文章記錄我學習的過程,並且將我所學到的知識分享給大家。
- 【Day 01】淺入淺出 Rails with Vue - Before We Begin
- 【Day 02】淺入淺出 Rails with Vue - Vue 的基本概念 - 1
- 【Day 03】淺入淺出 Rails with Vue - Vue 的基本概念 - 2
- 【Day 04】淺入淺出 Rails with Vue - Vue 的基本概念 - 3
- 【Day 05】淺入淺出 Rails with Vue - Vue 的基本概念 - 4
- 【Day 06】淺入淺出 Rails with Vue - Vue 的基本概念 - 5
- 【Day 07】淺入淺出 Rails with Vue - Vue 的基本概念 - 6
Modifier 是用 . 表示的特殊後綴,它可以用來修飾 v-bind 或 v-on 指令,例如:
<form v-on:submit.prevent="onSubmit"> ... </form>
上面的例子中,我們使用了 .prevent 修飾符,它會呼叫 event.preventDefault(),防止表單被送出。
在 Vue 中提供了一些簡寫的方式,用來簡化指令的撰寫,例如:
<!-- full syntax -->
<a v-bind:href="url"> ... </a>
<!-- shorthand -->
<a :href="url"> ... </a>
<!-- shorthand with dynamic argument (2.6.0+) -->
<a :[key]="url"> ... </a>
<!-- full syntax -->
<a v-on:click="doSomething"> ... </a>
<!-- shorthand -->
<a @click="doSomething"> ... </a>
<!-- shorthand with dynamic argument (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
以上的 : 和 @ 都是 valid 的,當我們使用 : 時,我們可以使用 v-bind 的所有修飾符,而 @ 則是 v-on 的所有修飾符。
In-template expressions 是非常方便的,但是他們比較適合用在簡單的運算,當越來越多的邏輯被加入到模板中時,將會讓模板更難以維護,例如以下的例子:
<div id="example">
  {{ message.split('').reverse().join('') }}
</div>
我們將 message 透過 split()、reverse()、join() 這三個函式來進行運算,這樣的寫法雖然可以達到我們的目的,但是這樣的寫法並不直覺,必須花一些時間理解,對於太多的邏輯運算我們可以使用 computed properties 來解決這個問題。
讓我們先從一個簡單的例子開始,我們將 message 透過 computed properties 來進行運算,以下是範例:
<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // a computed getter
    reversedMessage: function () {
      // `this` points to the vm instance
      return this.message.split('').reverse().join('')
    }
  }
})
在上面的範例中,我們定義了一個 computed properties,它的名稱是 reversedMessage,我們可以透過 vm.reversedMessage 來取得它的值,而它的值是透過 message 來進行運算的,這樣的寫法比較直覺,也比較好維護。
你可以打開瀏覽器的 console 來觀察 vm.reversedMessage 的值,當你修改 vm.message 的值時,vm.reversedMessage 的值也會跟著改變。
console.log(vm.reversedMessage) // => 'olleH'
vm.message = 'Goodbye'
console.log(vm.reversedMessage) // => 'eybdooG'
在先前的範例中,我們使用了 computed properties,但是你也可以使用 methods 來達到相同的效果,例如:
<p>Reversed message: "{{ reverseMessage() }}"</p>
// in component
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  methods: {
    reverseMessage: function () {
      return this.message.split('').reverse().join('')
    }
  }
})
在上面的範例中,我們使用了 methods 來達到相同的效果,但是這樣的寫法並不直覺,因為我們需要在模板中加入 (),這樣的寫法也比較沒有效率,因為每次呼叫 reverseMessage() 時,都會重新執行函式,而 computed properties 則是會透過 caching 來達到效率的提升。
需特別注意的是,computed properties 是基於它們的依賴進行緩存的,只有在它們的相依值發生改變時才會重新計算。
computed: {
  now: function () {
    return Date.now()
  }
}
在上面的範例中,now 這個 computed properties 會在每次呼叫時都會一樣,因為 Date.now() 不依賴於任何的值,所以它不會重新計算。
所以為什麼我們需要 Caching?當我們有一個非常耗時的運算時,如果沒有 Caching,那麼每次呼叫時都會重新計算,這樣會造成效能的問題,所以我們需要 Caching 來達到效率的提升。
Vue 提供了一個方法來監聽資料的變化,這個方法就是 watch,我們可以透過 watch 來監聽資料的變化,當資料發生變化時,我們可以透過 watch 來執行一些函式,例如:
<div id="demo">{{ fullName }}</div>
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },
  watch: {
    firstName: function (val) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
})
在上面的範例中,我們使用了 watch 來監聽 firstName 與 lastName 的變化,當它們發生變化時,我們會透過 watch 來執行一些函式,這樣的寫法比較沒有效率,因為我們需要在 watch 中寫入兩個函式,而且這兩個函式的內容是一樣的,所以我們可以透過 computed properties 來達到相同的效果,例如:
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})
computed properties 也可以設定 setter,例如:
// ...
computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}
// ...
在上面的範例中,我們設定了 fullName 的 setter,當我們呼叫 vm.fullName = 'John Doe' 時,setter 會被呼叫,並且會將 John Doe 分割成 firstName 與 lastName。